package module

import (
	"bytes"
	"fmt"
	"go/ast"
	"go/parser"
	"go/printer"
	"go/token"
	"os"
	"path/filepath"
	"server/cfg"
	"server/utils/db"
	"server/utils/file"
	"strings"
	"text/template"
	"unicode"
)

func Startup() {
	db.CreateDb(cfg.Config.Db.DbName)
	createAdminsTable()
}

func createAdminsTable() {
	db.Exec(`create table if not exists admins(
		id int not null primary key AUTO_INCREMENT,
		username varchar(16) not null default '' unique key,
		password varchar(32) not null default '',
		role varchar(16) not null default '',
		create_time timestamp not null default current_timestamp,
		update_time timestamp not null default current_timestamp on update current_timestamp
	)`)
	//默认插入开发者和管理员
	if db.Count("admins", "username=?", "developer") == 0 {
		db.Exec("insert into admins (username, password, role) values (?,?,?)", "developer", "96133168c1a51b09f6af55ef170f7173", "developer")
	}
	if db.Count("admins", "username=?", "admin") == 0 {
		db.Exec("insert into admins (username, password, role) values (?,?,?)", "admin", "e10adc3949ba59abbe56e057f20f883e", "admin")
	}
}

func CreateModuleTable(data map[string]any) error {
	table := data["table"].(map[string]any)
	tableName := table["name"].(string)
	query := "create table if not exists " + tableName + "(\n"
	query += "id" + " int not null primary key AUTO_INCREMENT"
	columns := table["columns"].([]any)
	if len(columns) == 0 {
		return nil
	}
	indexList := make([]string, 0)
	for i := 0; i < len(columns); i++ {
		column := columns[i].(map[string]any)
		_name := column["name"].(string)
		_type := column["type"].(string)
		_length := column["length"].(string)
		_unique := column["unique"].(bool)
		_index := column["index"].(bool)
		if _type == "varchar" {
			query += ",\n" + _name + " " + _type + "(" + _length + ") not null default ''"
		} else if _type == "timestamp" {
			query += ",\n" + _name + " " + _type + " not null default current_timestamp"
		} else {
			query += ",\n" + _name + " " + _type + " not null default 0"
		}
		if _unique {
			query += " unique key"
		}
		if _index {
			indexList = append(indexList, _name)
		}
	}
	query += ",\n" + "create_time timestamp not null default current_timestamp"
	query += ",\n" + "update_time timestamp not null default current_timestamp on update current_timestamp"
	for i := 0; i < len(indexList); i++ {
		query += ",\n" + "index (" + indexList[i] + ")"
	}
	query += "\n" + ")"
	fmt.Println(query)
	_, err := db.Db().Exec(query)
	if err != nil {
		return fmt.Errorf("创建表 "+tableName+" 失败：", err)
	}
	fmt.Println("已创建表：", tableName)
	return nil
}

// 创建服务端代码
func GenerateServerCode(data map[string]any) error {
	codeName := data["codeName"].(string)
	table := data["table"].(map[string]any)
	tableName := table["name"].(string)
	columns := table["columns"].([]any)

	//处理脚本
	templatePath := "./templates/server/handler.tem"
	savePath := "./handlers/" + codeName + ".go"
	SearchColumns := ""
	for i := 0; i < len(columns); i++ {
		column := columns[i].(map[string]any)
		_name := column["name"].(string)
		_type := column["type"].(string)
		if _type == "varchar" {
			if i > 0 {
				SearchColumns += "\n"
			}
			SearchColumns += "        whereList = append(whereList, \"" + _name + " like '%\" + searchText + \"%'\")"
		}
	}
	err := generateFromTemplate(templatePath, savePath, map[string]any{
		"TableName":     tableName,
		"LowerName":     codeName,
		"UpperName":     firstToUpper(codeName),
		"SearchColumns": SearchColumns,
	})
	if err != nil {
		return err
	}

	//路由
	templatePath = "./templates/server/route.tem"
	savePath = "./router/routes/" + codeName + ".go"
	upperName := firstToUpper(codeName)
	err = generateFromTemplate(templatePath, savePath, map[string]any{
		"LowerName": codeName,
		"UpperName": upperName,
	})
	if err != nil {
		return err
	}

	//添加引用
	err = addCalling(upperName + "Routes")
	return err
}

// 创建客户端代码
func GenerateClientCode(data map[string]any) error {
	menuName := data["menuName"].(string)
	codeName := data["codeName"].(string)
	icon := data["icon"].(string)
	menuOrder := int(data["menuOrder"].(float64))
	table := data["table"].(map[string]any)
	columns := table["columns"].([]any)

	//添加多语言词
	err := insertToFile("../admin/src/locale/zh-CN.ts", "...localeSettings", "  'menu."+codeName+"': '"+menuName+"',\n", "'menu."+codeName+"'")
	if err != nil {
		return err
	}

	//创建路由文件
	templatePath := "./templates/client/route.tem"
	savePath := "../admin/src/router/routes/modules/" + codeName + ".ts"
	upperName := firstToUpper(codeName)
	err = generateFromTemplate(templatePath, savePath, map[string]any{
		"LowerName": codeName,
		"UpperName": upperName,
		"Icon":      icon,
		"MenuOrder": menuOrder,
	})
	if err != nil {
		return err
	}

	//创建view文件
	templatePath = "./templates/client/view.tem"
	savePath = "../admin/src/views/" + codeName + "/index.vue"
	PopupDataModel := ""
	Columns := ""
	DivLoop := ""
	for i := 0; i < len(columns); i++ {
		column := columns[i].(map[string]any)
		_title := column["title"].(string)
		_name := column["name"].(string)
		_type := column["type"].(string)
		if i > 0 {
			PopupDataModel += "\n"
			Columns += "\n"
			DivLoop += "\n"
		}

		PopupDataModel += "    " + _name + ":"
		if _type == "varchar" {
			PopupDataModel += "'',"
		} else {
			PopupDataModel += "0,"
		}

		Columns += "  {\n"
		Columns += "    title: '" + _title + "',\n"
		Columns += "    dataIndex: '" + _name + "',\n"
		Columns += "  },"

		tag := "b-input"
		if _type != "varchar" {
			tag = "b-input-number"
		}
		DivLoop += "          <a-form-item field=\"" + _name + "\" :rules=\"[{ required:true, message:'" + _title + "不能为空' }]\" hide-label>\n"
		DivLoop += "            <" + tag + " title=\"" + _title + "\" title-width=\"110px\" v-model=\"popupData." + _name + "\" placeholder=\"输入" + _title + "\"/>\n"
		DivLoop += "          </a-form-item>"
	}
	err = generateFromTemplate(templatePath, savePath, map[string]any{
		"ObjName":        strings.Replace(menuName, "管理", "", 1),
		"LowerName":      codeName,
		"PopupDataModel": PopupDataModel,
		"Columns":        Columns,
		"DivLoop":        DivLoop,
	})
	if err != nil {
		return err
	}

	return err
}

// 读取模板并创建
func generateFromTemplate(templatePath, savePath string, data map[string]any) error {
	if file.IsExists(savePath) {
		fmt.Println(savePath, "已存在")
		return nil
	}
	content, err := os.ReadFile(templatePath)
	if err != nil {
		return fmt.Errorf("读取模板内容失败：%v", err)
	}
	tmpl, err := template.New("").Delims("[[", "]]").Parse(string(content))
	if err != nil {
		return fmt.Errorf("解析模板失败：%v", err)
	}
	dstDir := filepath.Dir(savePath)
	if err := os.MkdirAll(dstDir, 0755); err != nil {
		return err
	}
	outputFile, err := os.Create(savePath)
	if err != nil {
		return fmt.Errorf("创建保存文件失败：%v", err)
	}
	defer outputFile.Close()
	err = tmpl.Execute(outputFile, data)
	if err != nil {
		return fmt.Errorf("替换模板数据并保存失败：%v", err)
	}
	fmt.Println("已创建文件：", savePath)
	return nil
}

// 追加引用到根routes.go文件
func addCalling(funcName string) error {
	filePath := "router/routes.go"
	fileSet := token.NewFileSet()
	node, err := parser.ParseFile(fileSet, filePath, nil, parser.ParseComments)
	if err != nil {
		return fmt.Errorf("解析文件失败：%v", err)
	}

	// 检查代码是否已存在
	callExists := false
	ast.Inspect(node, func(n ast.Node) bool {
		callExpr, ok := n.(*ast.CallExpr)
		if !ok {
			return true
		}
		if selExpr, ok := callExpr.Fun.(*ast.SelectorExpr); ok {
			if x, ok := selExpr.X.(*ast.Ident); ok && x.Name == "routes" && selExpr.Sel.Name == funcName {
				callExists = true
				return false
			}
		}
		return true
	})
	if callExists {
		fmt.Println("调用已存在，无需重复添加")
		return nil
	}

	// 添加代码调用
	addSuccess := false
	ast.Inspect(node, func(n ast.Node) bool {
		fn, ok := n.(*ast.FuncDecl)
		if !ok || fn.Name.Name != "Setup" {
			return true
		}
		stmt := &ast.ExprStmt{
			X: &ast.CallExpr{
				Fun: &ast.SelectorExpr{
					X:   ast.NewIdent("routes"),
					Sel: ast.NewIdent(funcName),
				},
				Args: []ast.Expr{ast.NewIdent("rs")},
			},
		}
		fn.Body.List = append(fn.Body.List, stmt)
		addSuccess = true
		return false
	})
	if !addSuccess {
		return fmt.Errorf("添加代码调用失败")
	}

	// 保存文件
	var buf bytes.Buffer
	if err := printer.Fprint(&buf, fileSet, node); err != nil {
		return fmt.Errorf("生成代码失败：%v", err)
	}
	if err := os.WriteFile(filePath, buf.Bytes(), 0644); err != nil {
		return fmt.Errorf("写入文件失败：%v", err)
	}
	fmt.Println("已修改文件：", filePath)
	return nil
}

// 将字符串的首字母转换为大写
func firstToUpper(s string) string {
	r := []rune(s)
	r[0] = unicode.ToUpper(r[0])
	return string(r)
}

// 插入内容到文件指定位置(checkStr用于判断是否存在)
func insertToFile(filePath, pos, insertStr string, checkStr string) error {
	// 1. 读取文件内容
	content, err := os.ReadFile(filePath)
	if err != nil {
		return fmt.Errorf("读取文件失败: %v", err)
	}

	// 2. 转换为字符串并查找...localeSettings位置
	fileContent := string(content)
	if strings.Contains(fileContent, checkStr) {
		fmt.Println(checkStr, "已存在，无需添加")
		return nil
	}
	spreadPos := strings.Index(fileContent, pos)
	if spreadPos == -1 {
		return fmt.Errorf("未找到[" + pos + "]位置")
	}

	// 3. 计算插入位置(找到...前面的逗号和换行)
	insertPos := spreadPos
	for insertPos > 0 {
		if fileContent[insertPos-1] == '\n' {
			break
		}
		insertPos--
	}

	// 4. 插入新内容
	newContent := fileContent[:insertPos] + insertStr + fileContent[insertPos:]

	// 5. 写回文件
	err = os.WriteFile(filePath, []byte(newContent), 0644)
	if err != nil {
		return fmt.Errorf("写入文件失败: %v", err)
	}

	fmt.Println("修改成功，已插入:", insertStr)
	return nil
}
